package com.tbit.uqbike.webmanager.util.csv.entity;


import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import com.alibaba.nacos.common.utils.StringUtils;
import com.tbit.uqbike.webmanager.util.csv.annotations.Csv;
import com.tbit.uqbike.webmanager.util.csv.annotations.Sum;
import lombok.Data;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;


public class CsvWrite {

    Class tClass;
    File file;
    HashMap<String, BigDecimal> sumMap = new HashMap<>();
    List<FieldInfo> fieldInfos;

    public CsvWrite(Class tClass, File file) {
        this.tClass = tClass;
        this.file = file;
        init(tClass, file);
    }

    private static List<FieldInfo> getFieldInfos(Class<?> c) {
        try {
            List<FieldInfo> iInfos = new ArrayList<>();
            Field[] fields = c.getDeclaredFields();
            for (Field field : fields) {
                Csv csv = field.getDeclaredAnnotation(Csv.class);
                if (csv != null) {
                    String fieldName = field.getName();
                    Method method = c.getDeclaredMethod("get" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1));
                    FieldInfo fieldInfo = new FieldInfo();
                    fieldInfo.setCsv(csv);
                    fieldInfo.setField(field);
                    fieldInfo.setGetMethod(method);

                    Sum sum = field.getDeclaredAnnotation(Sum.class);
                    if (sum != null) {
                        fieldInfo.setSum(sum);
                    }
                    iInfos.add(fieldInfo);
                }
            }
            return iInfos;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 初始化
     *
     * @param tClass
     * @param file
     */
    private void init(Class<?> tClass, File file) {
        this.fieldInfos = extractFields(tClass);
        File parent = file.getParentFile();
        if (parent != null && !parent.exists()) {
            parent.mkdirs();
        }
        try {
            file.createNewFile();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 写标题
     */
    public void writeHead() {
        try (BufferedWriter buffWriter = new BufferedWriter(new FileWriter(file, true), 1024)) {
            buffWriter.write(new String(new byte[]{(byte) 0xEF, (byte) 0xBB, (byte) 0xBF}));

            StringBuffer buf = new StringBuffer();
            fieldInfos.forEach(v -> {
                String name = v.getCsv().name();
                buf.append("\"").append(name).append("\",");
            });
            buffWriter.write(buf.toString());
            buffWriter.newLine();
            buffWriter.flush();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 写汇总
     */
    public void writeSum() {
        NumberFormat nf = NumberFormat.getInstance();
        //默认是true,true的返回格式用,分隔开,格式如123,456,789.128，false则没有逗号
        nf.setGroupingUsed(false);
        try (BufferedWriter buffWriter = new BufferedWriter(new FileWriter(file, true), 1024)) {
            StringBuffer buf = new StringBuffer();
            for (int i = 0; i < fieldInfos.size(); i++) {
                String value;
                if (i == 0) {
                    value = "汇总";
                } else {
                    FieldInfo v = fieldInfos.get(i);
                    if (v.getSum() != null) {
                        String fieldName = v.getField().getName();
                        BigDecimal sumBigDecimal = sumMap.get(fieldName);
                        if (sumBigDecimal == null) {
                            sumBigDecimal = new BigDecimal("0");
                        }
                        value = nf.format(sumBigDecimal);
                    } else {
                        value = "";
                    }
                }
                buf.append("\t").append(value).append(",");
            }
            buffWriter.write(buf.toString());
            buffWriter.newLine();
            buffWriter.flush();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 写数据
     */
    public void writeList(List dataList) {
        NumberFormat nf = NumberFormat.getInstance();
        //默认是true,true的返回格式用,分隔开,格式如123,456,789.128，false则没有逗号
        nf.setGroupingUsed(false);
        try (BufferedWriter buffWriter = new BufferedWriter(new FileWriter(file, true), 1024)) {
            if (!dataList.isEmpty()) {
                StringBuffer buf = null;
                for (Object row : dataList) {
                       buf = new StringBuffer("");
                    for (FieldInfo v : fieldInfos) {
                        Object o = v.getMethod.invoke(row);
                        //空处理
                        if (o == null) {
                            o = "";
                        }

                        //时间处理
                        if (o instanceof Date) {
                            String datePattern = v.getCsv().datePattern();
                            o = DateUtil.format((Date) o, datePattern);
                        }
                        //double数字处理
                        if (o instanceof Double){
                            o = nf.format(o);
                        }

                        //值转换
                        String[] keys = v.getCsv().keys();
                        String[] values = v.getCsv().values();
                        for (int i = 0; i < keys.length; i++) {
                            if (keys[i].equals(o.toString())) {
                                o = values[i];
                            }
                        }

                        String commaReplace = v.getCsv().commaReplace();
                        if (StringUtils.isNotBlank(commaReplace) && o instanceof String) {
                            o = ((String) o).replace(",", commaReplace);
                        }
                        //防止单个数据里面也存在,号
                        if (o.toString().contains(",")) {
                            o = o.toString().replace(",", "，");
                        }


                        // 过滤掉换行符和回车符
                        String filteredString = o.toString().replaceAll("[\\r\\n\\u0085\\u2028\\u2029]", "").trim();

                        // 添加到缓冲区 .append(prefix)
                        buf.append("\t").append(filteredString).append(",");
                        //汇总信息计算
                        if (v.getSum() != null) {
                            String fieldName = v.getField().getName();
                            BigDecimal sumBigDecimal = sumMap.get(fieldName);
                            if (sumBigDecimal == null) {
                                sumBigDecimal = new BigDecimal("0");
                            }
                            sumBigDecimal = NumberUtil.add(sumBigDecimal, NumberUtil.toBigDecimal(o.toString()));
                            sumMap.put(fieldName, sumBigDecimal);
                        }
                    }
                    buffWriter.write(buf.toString());
                    buffWriter.newLine();
                    buffWriter.flush();
                }
            }
            buffWriter.close();
            dataList.clear();
            dataList = null;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private List<FieldInfo> extractFields(Class<?> c) {
        List<FieldInfo> iInfos = new ArrayList<>();
        iInfos.addAll(getFieldInfos(c));
        iInfos.addAll(getFieldInfos(c.getSuperclass()));
        return iInfos;
    }


    /**
     * 写数据
     */
    public void writeListV1(List dataList) {
        try(BufferedWriter buffWriter = new BufferedWriter(new FileWriter(file, true), 1024);){
            if (!dataList.isEmpty()) {
                StringBuffer buf = null;
                for (Object row : dataList) {
                    buf = new StringBuffer("");
                    for (FieldInfo v : fieldInfos) {
                        Object o = v.getMethod.invoke(row);
                        //空处理
                        if (o == null) {
                            o = "";
                        }

                        //csv防止字符串精度丢失
//                        String prefix = "";
//                        if (!(o instanceof Number)) {
//                            prefix = "";
//                        }
                        String prefix = v.getCsv().type();


                        //时间处理
                        if (o instanceof Date) {
                            String datePattern = v.getCsv().datePattern();
                            o = DateUtil.format((Date) o, datePattern);
                        }

                        //值转换
                        String[] keys = v.getCsv().keys();
                        String[] values = v.getCsv().values();
                        for (int i = 0; i < keys.length; i++) {
                            if (keys[i].equals(o.toString())) {
                                o = values[i];
                            }
                        }

                        String commaReplace = v.getCsv().commaReplace();
                        if (StringUtils.isNotBlank(commaReplace) && o instanceof String) {
                            o = ((String) o).replace(",", commaReplace);
                        }
                        //防止单个数据里面也存在,号
                        if (o.toString().contains(",")) {
                            o = o.toString().replace(",", "，");
                        }

//                        buf.append("\t").append(prefix + o).append(",").toString();

                        // 过滤掉换行符和回车符
                        String filteredString = o.toString().replaceAll("[\\r\\n\\u0085\\u2028\\u2029]", "").trim();

                        // 添加到缓冲区
                        buf.append("\t").append(prefix).append(filteredString).append(",");
                        //汇总信息计算
                        if (v.getSum() != null) {
                            String fieldName = v.getField().getName();
                            BigDecimal sumBigDecimal = sumMap.get(fieldName);
                            if (sumBigDecimal == null) {
                                sumBigDecimal = new BigDecimal("0");
                            }
                            sumBigDecimal = NumberUtil.add(sumBigDecimal, NumberUtil.toBigDecimal(o.toString()));
                            sumMap.put(fieldName, sumBigDecimal);
                        }

                    }
                    buffWriter.write(buf.toString());
                    buffWriter.newLine();
                    buffWriter.flush();
//                    buffWriter.close();
                }
            }
            buffWriter.close();
//            buffWriter.flush();
//            dataList.clear();
//            dataList = null;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Data
    public static class FieldInfo {
        public Field field;
        public Method getMethod;
        public Csv csv;
        public Sum sum;
    }

}
